package com.sikaryofficial.information.manager;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.sikaryofficial.common.core.exception.ServiceException;
import com.sikaryofficial.common.redis.service.RedisService;
import com.sikaryofficial.common.security.utils.SecurityUtils;
import com.sikaryofficial.information.config.HISMKInformationProperties;
import com.sikaryofficial.information.constant.ArticleLabelEnum;
import com.sikaryofficial.information.domain.entity.Article;
import com.sikaryofficial.information.domain.mapping.ArticleMapping;
import com.sikaryofficial.information.service.IArticleService;
import com.sikaryofficial.information.service.articleview.ArticleViewEvent;
import com.sikaryofficial.system.api.model.infomation.ArticleDTO;
import com.sikaryofficial.system.api.model.infomation.ArticleListReq;
import com.sikaryofficial.system.api.model.infomation.KolListReq;
import com.sikaryofficial.system.api.model.infomation.StatuteListReq;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import static com.sikaryofficial.common.core.constant.CacheBusinessConstants.*;

/**
 * @author : qinjinyuan
 * @desc :  文章数据同步管理类
 * @date : 2024/03/13 11:50
 */
@Component
@Slf4j
public class ArticleManager {
    @Autowired
    private IArticleService articleService;
    @Autowired
    private HISMKInformationProperties brandTenantProperties;
    @Autowired
    private RedisService redisService;
    @Resource
    private ApplicationEventPublisher publisher;

    /**
     * 文章删除
     *
     * @param articleIds
     * @return
     */
    public Boolean remove(String articleIds) {
        if (CharSequenceUtil.isBlank(articleIds)) {
            return false;
        }
        List<Long> articleIdList = Lists.newArrayList();
        Arrays.stream(articleIds.split(",")).forEach(
                item -> articleIdList.add(Long.parseLong(item))
        );
        return articleService.update(new LambdaUpdateWrapper<Article>()
                .setSql(" deleted_version= article_id ")
                .set(Article::getUpdatedBy, SecurityUtils.getUserId())
                .set(Article::getUpdatedTime, new Date())
                .in(Article::getArticleId, articleIdList)
        );
    }

    public Boolean removeOwner(String articleIds) {
        if (CharSequenceUtil.isBlank(articleIds)) {
            return false;
        }
        List<Long> articleIdList = Lists.newArrayList();
        Arrays.stream(articleIds.split(",")).forEach(
                item -> articleIdList.add(Long.parseLong(item))
        );
        return articleService.update(new LambdaUpdateWrapper<Article>()
                .setSql(" deleted_version= article_id ")
                .set(Article::getUpdatedBy, SecurityUtils.getUserId())
                .set(Article::getUpdatedTime, new Date())
                .eq(Article::getCreatedBy, SecurityUtils.getUserId())
                .eq(Article::getDeletedVersion, 0L)
                .in(Article::getArticleId, articleIdList)
        );
    }

    /**
     * 文章详情
     *
     * @param articleId
     * @return
     */
    public ArticleDTO getInfo(Long articleId) {
        Article article = articleService.getOne(new LambdaQueryWrapper<Article>()
                .eq(Article::getArticleId, articleId)
                .eq(Article::getDeletedVersion, 0L)
        );
        if (Objects.isNull(article)) {
            throw new ServiceException("the article is not exist");
        }
        /**
         * 查询  评价、 点赞、收藏 数量
         */
        // 5、查阅量数据增加
        Integer tenantId = brandTenantProperties.getTenantByBrand(SecurityUtils.getBrand());
        Integer auditStatus = article.getAuditStatus();
        publisher.publishEvent(new ArticleViewEvent(articleId, tenantId, auditStatus));
        return ArticleMapping.INSTANCE.coverToDTO(article);
    }

    /**
     * @param articleId
     * @return
     */
    public ArticleDTO getSimpleInfo(Long articleId) {
        Article article = articleService.getOne(new LambdaQueryWrapper<Article>()
                .select(Article::getArticleId,
                        Article::getArticleType, Article::getAuditStatus,
                        Article::getHeadline,
                        Article::getEditType, Article::getContentType,
                        Article::getArticleSite,
                        Article::getHasOriginal,
                        Article::getSource,
                        Article::getPublishTime,
                        Article::getCreatedBy)
                .eq(Article::getArticleId, articleId)
                .eq(Article::getDeletedVersion, 0L)
        );
        if (Objects.isNull(article)) {
            return null;
        }
        return ArticleMapping.INSTANCE.coverToDTO(article);
    }

    /**
     * 文章分页列表
     * <p>
     * 由于需要按点击量排序，所以需要缓存
     * <p>
     * 阅读量 来排序
     *
     * @param req
     * @return
     */
    public IPage<ArticleDTO> listPage(ArticleListReq req) {
        // 分页查询文章数据：按照文章查阅量进行排序
        Page<ArticleDTO> customerPage = new Page<>(req.getPageNum(), req.getPageSize());
        Integer tenantId = brandTenantProperties.getTenantByBrand(SecurityUtils.getBrand());
        req.setTenantId(tenantId);
        // 缓存数据
        String md5 = generateCacheKey(req);
        String cacheKey = MessageFormat.format(ARTICLE_PAGE_LIST_KEY, md5);
        if (Boolean.TRUE.equals(redisService.hasKey(cacheKey))) {
            JSONObject cacheValue = redisService.getCacheObject(cacheKey);
            return Objects.nonNull(cacheValue) ? JSON.parseObject(cacheValue.toString(), new TypeReference<IPage<ArticleDTO>>() {
            }) : null;
        }
        Long userId = SecurityUtils.getUserId();
        String ownerArticleCacheKey = MessageFormat.format(ARTICLE_OWNER_LATEST_LIST_KEY, userId.toString(), tenantId.toString());
        if (Boolean.TRUE.equals(redisService.hasKey(ownerArticleCacheKey))) {
            List<ArticleDTO> ownerArticleList = redisService.getCacheObject(ownerArticleCacheKey);
            req.setNotContainArticleId(CollUtil.isNotEmpty(ownerArticleList) ? ownerArticleList.iterator().next().getArticleId() : null);
        }
        // 分页查询数据
        IPage<ArticleDTO> articleDTOIPage = articleService.articleList(customerPage, req);
        articleDTOIPage.getRecords().forEach(item -> {
            if (Objects.nonNull(item.getArticleLabel())) {
                item.setArticleLabelDesc(ArticleLabelEnum.getNameByCode(item.getArticleLabel()).getName());
            }
        });
        if (CollUtil.isNotEmpty(articleDTOIPage.getRecords())) {
            redisService.setCacheObject(cacheKey, articleDTOIPage, 1L, TimeUnit.MINUTES);
        } else {
            redisService.setCacheObject(cacheKey, articleDTOIPage, 10L, TimeUnit.SECONDS);
        }
        return articleDTOIPage;
    }

    public IPage<ArticleDTO> statuteListPage(StatuteListReq req) {
        Integer tenantId = brandTenantProperties.getTenantByBrand(SecurityUtils.getBrand());
        req.setTenantId(tenantId);
        // 分页查询文章数据：按照文章查阅量进行排序
        Page<ArticleDTO> customerPage = new Page<>(req.getPageNum(), req.getPageSize());
        // 缓存数据
        String md5 = generateCacheKey(req);
        String cacheKey = MessageFormat.format(ARTICLE_STATUTE_PAGE_LIST_KEY, md5);
        if (Boolean.TRUE.equals(redisService.hasKey(cacheKey))) {
            JSONObject cacheValue = redisService.getCacheObject(cacheKey);
            return Objects.nonNull(cacheValue) ? JSON.parseObject(cacheValue.toString(), new TypeReference<IPage<ArticleDTO>>() {
            }) : null;
        }
        IPage<ArticleDTO> articleDTOIPage = articleService.statuteListPage(customerPage, req);
        if (CollUtil.isNotEmpty(articleDTOIPage.getRecords())) {
            redisService.setCacheObject(cacheKey, articleDTOIPage, 1L, TimeUnit.MINUTES);
        } else {
            redisService.setCacheObject(cacheKey, articleDTOIPage, 10L, TimeUnit.SECONDS);
        }
        return articleDTOIPage;
    }

    private String generateCacheKey(StatuteListReq req) {
        String userIdStr = Objects.nonNull(SecurityUtils.getUserId()) ? SecurityUtils.getUserId().toString() : "";
        String country = CharSequenceUtil.isNotBlank(req.getCountry()) ? req.getCountry() : "";
        String area = CharSequenceUtil.isNotBlank(req.getArea()) ? req.getArea() : "";
        String startTimeStr = Objects.nonNull(req.getPublishStartTime()) ? req.getPublishStartTime().getTime() + "" : "";
        String endTimeStr = Objects.nonNull(req.getPublishEndTime()) ? req.getPublishEndTime().getTime() + "" : "";
        return DigestUtil.md5Hex(req.getPageNum() + "_"
                + req.getPageSize() + "_"
                + userIdStr + "_"
                + country + "_"
                + area + "_"
                + startTimeStr + "_"
                + endTimeStr
        );
    }

    /**
     * 生成缓存key
     * 分页no + 分页size +
     *
     * @param req
     * @return
     */
    private String generateCacheKey(ArticleListReq req) {
        String userIdStr = Objects.nonNull(SecurityUtils.getUserId()) ? SecurityUtils.getUserId().toString() : "";
        String articleLabelStr = Objects.nonNull(req.getArticleLabel()) ? req.getArticleLabel().toString() : "";
        return DigestUtil.md5Hex(req.getPageNum() + "_"
                + req.getPageSize() + "_"
                + userIdStr + "_"
                + articleLabelStr
        );
    }

    public IPage<ArticleDTO> kolListPage(KolListReq req) {
        Integer tenantId = brandTenantProperties.getTenantByBrand(SecurityUtils.getBrand());
        req.setTenantId(tenantId);
        // 分页查询文章数据：按照文章查阅量进行排序
        Page<ArticleDTO> customerPage = new Page<>(req.getPageNum(), req.getPageSize());
        // 缓存数据
        String md5 = generateCacheKolKey(req);
        String cacheKey = MessageFormat.format(ARTICLE_KOL_PAGE_LIST_KEY, md5);
        if (Boolean.TRUE.equals(redisService.hasKey(cacheKey))) {
            JSONObject cacheValue = redisService.getCacheObject(cacheKey);
            return Objects.nonNull(cacheValue) ? JSON.parseObject(cacheValue.toString(), new TypeReference<IPage<ArticleDTO>>() {
            }) : null;
        }
        IPage<ArticleDTO> articleDTOIPage = articleService.kolListPage(customerPage, req);
        articleDTOIPage.getRecords().forEach(item -> {
            if (Objects.nonNull(item.getArticleLabel())) {
                item.setArticleLabelDesc(ArticleLabelEnum.getNameByCode(item.getArticleLabel()).getName());
            }
        });
        if (CollUtil.isNotEmpty(articleDTOIPage.getRecords())) {
            redisService.setCacheObject(cacheKey, articleDTOIPage, 1L, TimeUnit.MINUTES);
        } else {
            redisService.setCacheObject(cacheKey, articleDTOIPage, 10L, TimeUnit.SECONDS);
        }
        return articleDTOIPage;
    }

    private String generateCacheKolKey(KolListReq req) {
        String userIdStr = Objects.nonNull(SecurityUtils.getUserId()) ? SecurityUtils.getUserId().toString() : "";
        return DigestUtil.md5Hex(req.getPageNum() + "_"
                + req.getPageSize() + "_"
                + userIdStr
        );
    }

    public List<ArticleDTO> ownerLatest() {
        // 缓存数据
        Long userId = SecurityUtils.getUserId();
        Integer tenantId = brandTenantProperties.getTenantByBrand(SecurityUtils.getBrand());
        String cacheKey = MessageFormat.format(ARTICLE_OWNER_LATEST_LIST_KEY, userId.toString(), tenantId.toString());
        log.info("ownerLatest cacheKey:{}", cacheKey);
        if (Boolean.TRUE.equals(redisService.hasKey(cacheKey))) {
            return redisService.getCacheObject(cacheKey);
        }
        List<ArticleDTO> articleDTOIPage = articleService.ownerLatest(userId, tenantId);
        if (CollUtil.isNotEmpty(articleDTOIPage)) {
            redisService.setCacheObject(cacheKey, articleDTOIPage, 1L, TimeUnit.MINUTES);
        } else {
            redisService.setCacheObject(cacheKey, Lists.newArrayList(), 10L, TimeUnit.SECONDS);
        }
        return articleDTOIPage;
    }

}
